//------------------------------------------------------------
//  Filename: tcdm_lint_mux.sv
//   
//  Author  : wlduan@gmail.com
//  Revise  : 2019-10-17 12:08
//  Description: 
//   
//  Copyright (C) 2014, YRBD, Inc. 					      
//  All Rights Reserved.                                       
//-------------------------------------------------------------
//
`timescale 1ns/1ps
 
module tcdm_lint_mux #(
    parameter ADDR_WIDTH = 32,
    parameter DATA_WIDTH = 32,
    parameter BE_WIDTH   = DATA_WIDTH/8,
    parameter N_PORTS    = 2
)
( 
    input clk,  
    input rst_n,  
     
    LINT_IF.Slave  lint_slave[N_PORTS],
    LINT_IF.Master lint_master
);      
//-------------------------------------------------------------
logic [N_PORTS-1:0]     active_req_i;
logic [N_PORTS-1:0]     active_rrvs;
logic [N_PORTS-1:0]     active_comp;
logic [N_PORTS-1:0]     active_prev;
logic [N_PORTS-1:0]     active_mask;
logic [N_PORTS-1:0]     active_expc;
logic [2*N_PORTS-1:0]   active_dreq;
logic [2*N_PORTS-1:0]   active_dxpc;
//-------------------------------------------------------------
logic [N_PORTS-1:0]     active_i;
logic [N_PORTS-1:0]     active_q;
logic [N_PORTS-1:0]     active_int;
//-------------------------------------------------------------
always_ff @(posedge clk,negedge rst_n) begin
    if(rst_n == 0)begin 
        active_prev <= 'b0; 
    end 
    else begin 
        active_prev <= active_expc; 
    end 
end 
//-------------------------------------------------------------
assign active_rrvs = ~active_prev - active_prev;
assign active_comp = active_rrvs + 1'b1;
assign active_mask = active_comp;
assign active_dreq = {active_req_i,{active_mask&active_req_i}};
assign active_expc = active_dxpc[0       +: N_PORTS]|
                     active_dxpc[N_PORTS +: N_PORTS];
//-------------------------------------------------------------
always_comb begin
    active_dxpc = '0;
    for(reg[7:0] i=0;i<2*N_PORTS;i++) begin
        if(active_dreq[i]) begin 
            active_dxpc = 'b1 << i;
            break;
        end
    end    
end
//-------------------------------------------------------------
assign lint_master.data_req = |active_req_i;
assign active_i = active_expc;
//-------------------------------------------------------------
always_ff @(posedge clk,negedge rst_n) begin
    if(rst_n == 0)begin 
        active_q <= 'b0; 
    end 
    else begin 
        active_q <= active_int; 
    end 
end 
//-------------------------------------------------------------
enum logic[7:0] {IDLE,WAIT_GNT,WAIT_VLD} cs,ns;
//-------------------------------------------------------------
always_ff @(posedge clk,negedge rst_n) begin
    if(rst_n == 0)begin 
        cs <= IDLE; 
    end 
    else begin 
        cs <= ns; 
    end 
end 
//-------------------------------------------------------------
always_comb begin
    ns = cs;
    active_int = active_q;
    case(cs)
        IDLE: begin
            if(lint_master.data_req) begin
                active_int = active_i;
                if(lint_master.data_gnt) begin
                    ns = WAIT_VLD;
                end
                else begin
                    ns = WAIT_GNT;
                end
            end
        end
        WAIT_GNT: begin
            if(lint_master.data_gnt) begin 
                ns = WAIT_VLD;
            end
        end
        WAIT_VLD: begin
            if(lint_master.data_r_valid) begin
                if(lint_master.data_req) begin
                    active_int = active_i;
                    if(lint_master.data_gnt) begin
                        ns = WAIT_VLD;
                    end
                    else begin
                        ns = WAIT_GNT;
                    end
                end 
                else begin
                    ns = IDLE;
                end  
            end
        end
    endcase
end
//-------------------------------------------------------------
logic [N_PORTS*ADDR_WIDTH-1:0] ports_data_addr;
logic [N_PORTS*BE_WIDTH-1:0]   ports_data_be;
logic [N_PORTS -1:0]           ports_data_we;
logic [N_PORTS*DATA_WIDTH-1:0] ports_data_wdata;
//-------------------------------------------------------------
always_comb begin
    lint_master.data_addr  = 'b0;
    lint_master.data_wdata = 'b0;
    lint_master.data_we    = 'b0;
    lint_master.data_be    = 'b0;
    for(reg[7:0] i=0;i<N_PORTS;i++) begin
        if((((cs == IDLE)||(cs == WAIT_VLD))&active_i[i])||
            ((cs == WAIT_GNT)&active_q[i])) begin
            lint_master.data_addr  = ports_data_addr[ADDR_WIDTH*i +:ADDR_WIDTH];
            lint_master.data_wdata = ports_data_wdata[DATA_WIDTH*i +:DATA_WIDTH];
            lint_master.data_we    = ports_data_we[i];
            lint_master.data_be    = ports_data_be[BE_WIDTH*i +:BE_WIDTH];
        end
    end
end
//-------------------------------------------------------------
generate 
    genvar i;
    for(i=0;i<N_PORTS;i++) begin
        assign active_req_i[i]                            = lint_slave[i].data_req;
        assign ports_data_addr[ADDR_WIDTH*i +:ADDR_WIDTH] = lint_slave[i].data_addr;
        assign ports_data_be[BE_WIDTH*i +:BE_WIDTH]       = lint_slave[i].data_be;
        assign ports_data_we[i]                           = lint_slave[i].data_we;
        assign ports_data_wdata[DATA_WIDTH*i +:DATA_WIDTH]= lint_slave[i].data_wdata;
        always_comb begin
            lint_slave[i].data_gnt = 1'b0;
            if((((cs == IDLE)||(cs == WAIT_VLD))&active_i[i])||
                ((cs == WAIT_GNT)&active_q[i])) begin
                lint_slave[i].data_gnt = lint_master.data_gnt;
            end
        end
        always_comb begin
            lint_slave[i].data_r_rdata = 'b0;
            lint_slave[i].data_r_valid = 1'b0;
            lint_slave[i].data_r_opc   = 1'b0;
            if((cs == WAIT_VLD)&active_q[i]) begin
                lint_slave[i].data_r_rdata = lint_master.data_r_rdata;
                lint_slave[i].data_r_valid = lint_master.data_r_valid;
                lint_slave[i].data_r_opc   = lint_master.data_r_opc;
            end
        end        
    end
endgenerate
//-------------------------------------------------------------
 
      
endmodule
